package com.gitee.apanlh.spring;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * 	SpringApplicationContext工具类
 * 
 * 	@author Pan
 */
@Component
public class BeanContextUtils implements ApplicationContextAware, BeanFactoryPostProcessor {
	
	/** bean工厂实例 */ 
	private static ConfigurableListableBeanFactory beanFactory;
	/** 上下文实例 */
	private static ApplicationContext applicationContext;
	/** 是否加载上下文路径 */
	private boolean loadRequestMapping;
	
	/**
	 * 	默认构造函数
	 * 	<br>不初始化Request上下文
	 * 
	 * 	@author Pan
	 */
	public BeanContextUtils() {
		this(false);
	}
	
	/**	
	 * 	构造函数-加载上下文路径
	 * 	
	 * 	@author Pan
	 * 	@param 	loadRequestMapping true加载RequestMapping
	 */
	public BeanContextUtils(boolean loadRequestMapping) {
		this.loadRequestMapping = loadRequestMapping;
	}
	
	/**
	 *  Application加载顺序的问题，先加载ConfigurableListableBeanFactory使用获取bean操作
	 *  
	 *  @author Pan
	 */
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
		if (BeanContextUtils.beanFactory == null) {
			setBeanContext(configurableListableBeanFactory);
		}
		initLoad();
	}
	
	/**
	 * 	默认不加载上下文的路径
	 * 
	 *	@author Pan
	 */
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		if (applicationContext == null) {
			throw new NullPointerException("application context is null");
		}
		if (BeanContextUtils.applicationContext == null) {
			setBeanContext(applicationContext);
		}
		initLoad();
	}
	
	/**
	 * 	初始化加载
	 * 	
	 * 	@author Pan
	 */ 
	void initLoad() {
		if (loadRequestMapping) {
			ServletBeanUtils.initGetRequestMapping(); 
		}
	}
	
	/**	
	 * 	获取上下文
	 * 	@author Pan
	 * 	@return	ApplicationContext
	 */
	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}
	
	/**	
	 * 	根据Name获取Bean
	 * 	
	 * 	@author Pan
	 * 	@param  name 	bean名称
	 * 	@return	Object
	 */
	public static Object getBean(String name) throws BeansException {
		return getFactory().getBean(name);
	}
	
	/**
	 * 	根据Class获取Bean
	 * 	
	 * 	@author Pan
	 * 	@param  <T>  	数据类型
	 * 	@param  clazz	指定类
	 * 	@return	T
	 * 	@throws BeansException 抛出
	 */
	public static <T> T getBean(Class<T> clazz) {
		return getFactory().getBean(clazz);
	}
	
	/**	
	 * 	根据名字获取Bean，自定义转换类
	 * 	
	 * 	@author Pan
	 * 	@param  <T>  	数据类型
	 * 	@param  name		bean名称
	 * 	@param  clazz		指定类
	 * 	@return	T
	 * 	@throws BeansException	抛出
	 */
	public static <T> T getBean(String name, Class<T> clazz) throws BeansException {
		return getFactory().getBean(name, clazz);
	}
	
	/**	
	 * 	设置Bean
	 * 	
	 * 	@author Pan
	 * 	@param 	listableBeanFactory	BeanFactory子接口
	 */
	private static void setBeanContext(ListableBeanFactory listableBeanFactory) {
		if (listableBeanFactory instanceof ApplicationContext) {
			applicationContext = (ApplicationContext) listableBeanFactory;
			return ;
		}
		beanFactory = (ConfigurableListableBeanFactory) listableBeanFactory;
	}
	
	/**	
	 * 	获取工厂类
	 * 
	 * 	@author Pan
	 * 	@return ListableBeanFactory
	 */
	public static ListableBeanFactory getFactory() {
		return applicationContext == null ? beanFactory : applicationContext;
	}
}
